package com.springboot.cloud.sysadmin.organization.service.impl;

//import com.alicp.jetcache.anno.CacheInvalidate;
//import com.alicp.jetcache.anno.CacheType;
//import com.alicp.jetcache.anno.CacheUpdate;
//import com.alicp.jetcache.anno.Cached;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.cloud.sysadmin.organization.dao.ResourceMapper;
import com.springboot.cloud.sysadmin.organization.entity.param.ResourceQueryParam;
import com.springboot.cloud.sysadmin.organization.entity.po.*;
import com.springboot.cloud.sysadmin.organization.events.EventSender;
import com.springboot.cloud.sysadmin.organization.service.IResourceService;
import com.springboot.cloud.sysadmin.organization.service.IRoleResourceService;
import com.springboot.cloud.sysadmin.organization.service.IRoleService;
import com.springboot.cloud.sysadmin.organization.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created by ZengJian on 2021/2/3 0003 上午 9:22
 */

@Service
@Slf4j
public class ResourceService extends ServiceImpl<ResourceMapper, Resource> implements IResourceService {

    @Autowired
    private   IRoleResourceService roleResourceService;
    @Autowired
    private   IRoleService roleService;
    @Autowired
    private   IUserService userService;

    @Override
    public boolean add(Resource resource) {
        Resource resource1 = this.getOne(new QueryWrapper<Resource>()
                .eq(StrUtil.isNotBlank(resource.getCode()), "code", resource.getCode())
                .or(i -> i.eq(StrUtil.isNotBlank(resource.getCode()), "code", resource.getCode())
                        .eq("deleted", "Y")), false);
        Resource resource2 = this.getOne(new QueryWrapper<Resource>()
                .and(i -> i.eq(StrUtil.isNotBlank(resource.getUrl()), "url", resource.getUrl())
                        .eq(StrUtil.isNotBlank(resource.getMethod()), "method", resource.getMethod()))
                .or(i -> i.eq(StrUtil.isNotBlank(resource.getUrl()), "url", resource.getUrl())
                        .eq(StrUtil.isNotBlank(resource.getMethod()), "method", resource.getMethod())
                        .eq("deleted", "Y")), false);
        if (ObjectUtil.isNull(resource1) && ObjectUtil.isNull(resource2)) {
//            eventSender.send(BusConfig.ROUTING_KEY, resource);
            return this.save(resource);
        }
        return false;
    }

    @Override
    @Transactional
//    @CacheInvalidate(name="resource::", key = "#id")
    public boolean delete(Set<String> ids) {

        return this.removeByIds(ids);
    }

    @Override
    @Transactional
//    @CacheInvalidate(name="resource::",key = "#resource.id")
    public boolean update(Resource resource) {
        List<Resource> resource1 = this.list(new QueryWrapper<Resource>()
                .eq(StrUtil.isNotBlank(resource.getCode()), "code", resource.getCode())
                .or(i -> i.eq(StrUtil.isNotBlank(resource.getCode()), "code", resource.getCode())
                        .eq("deleted", "Y")));
        List<Resource> resource2 = this.list(new QueryWrapper<Resource>()
                .and(i -> i.eq(StrUtil.isNotBlank(resource.getUrl()), "url", resource.getUrl())
                        .eq(StrUtil.isNotBlank(resource.getMethod()), "method", resource.getMethod()))
                .or(i -> i.eq(StrUtil.isNotBlank(resource.getUrl()), "url", resource.getUrl())
                        .eq(StrUtil.isNotBlank(resource.getMethod()), "method", resource.getMethod())
                        .eq("deleted", "Y")));
        List<Resource> resource4 = this.list(new QueryWrapper<Resource>()
                .eq(StrUtil.isNotBlank(resource.getId()), "id", resource.getId())
                .eq(StrUtil.isNotBlank(resource.getCode()), "code", resource.getCode())
                .or(i -> i.eq(StrUtil.isNotBlank(resource.getCode()), "code", resource.getCode())
                        .eq("deleted", "Y")));
        List<Resource> resource5 = this.list(new QueryWrapper<Resource>()
                .and(i -> i.eq(StrUtil.isNotBlank(resource.getUrl()), "url", resource.getUrl())
                        .eq(StrUtil.isNotBlank(resource.getMethod()), "method", resource.getMethod())
                        .eq(StrUtil.isNotBlank(resource.getId()), "id", resource.getId()))
                .or(i -> i.eq(StrUtil.isNotBlank(resource.getUrl()), "url", resource.getUrl())
                        .eq(StrUtil.isNotBlank(resource.getMethod()), "method", resource.getMethod())
                        .eq(StrUtil.isNotBlank(resource.getId()), "id", resource.getId())
                        .eq("deleted", "Y")));
        log.debug("size1:" + resource1.size() + ":resource2:" + resource2.size());
        if (resource1.size() <= 1 && resource2.size() <= 1 && resource4.size() == resource1.size() && resource5.size() == resource2.size()) {
            Resource resource3 = this.getById(resource.getId());

            if (ObjectUtil.isNull(resource3)) {
                log.debug("1:" + Objects.isNull(resource3));
                return false;
            }
            return this.updateById(resource);
        }
        log.debug("2");
        return false;
    }

    @Override
    public List<Resource> queryByParentId(String id) {
        return this.list(new QueryWrapper<Resource>().eq("parent_id", id));
    }

    @Override
//    @Cached(name = "resource::", key = "#id", cacheType = CacheType.BOTH)
    public Resource get(String id) {
        return this.getById(id);
    }

    @Override
    public boolean getResource(String id) {
        Resource resource = this.getById(id);
        if (ObjectUtil.isNull(resource)) {
            return false;
        }
        return true;
    }

    @Override
    @Transactional
    public IPage<Resource> query(Page page, ResourceQueryParam resourceQueryParam) {
        SimpleDateFormat convert = new SimpleDateFormat("yyyy-MM-dd");
        QueryWrapper<Resource> queryWrapper = resourceQueryParam.build();
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getName()), "name", resourceQueryParam.getName());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getType()), "type", resourceQueryParam.getType());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getCode()), "code", resourceQueryParam.getCode());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getUrl()), "url", resourceQueryParam.getUrl());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getMethod()), "method", resourceQueryParam.getMethod());
        if (resourceQueryParam.getCreatedTimeStart() != null && resourceQueryParam.getCreatedTimeEnd() != null) {
            queryWrapper.apply("date_format(created_time,'%Y-%m-%d') >= date_format('" + convert.format(resourceQueryParam.getCreatedTimeStart()) + "','%Y-%m-%d')");
            queryWrapper.apply("date_format(created_time,'%Y-%m-%d') <= date_format('" + convert.format(resourceQueryParam.getCreatedTimeEnd()) + "','%Y-%m-%d')");
        }
        if (!resourceQueryParam.getEnabled()) {
            queryWrapper.eq("enabled", 0);
        }
        return this.page(page, queryWrapper);
    }

    @Override
    @Transactional
    public List<Resource> query(ResourceQueryParam resourceQueryParam) {
        SimpleDateFormat convert = new SimpleDateFormat("yyyy-MM-dd");
        QueryWrapper<Resource> queryWrapper = resourceQueryParam.build();
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getName()), "name", resourceQueryParam.getName());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getType()), "type", resourceQueryParam.getType());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getCode()), "code", resourceQueryParam.getCode());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getUrl()), "url", resourceQueryParam.getUrl());
        queryWrapper.like(StrUtil.isNotBlank(resourceQueryParam.getMethod()), "method", resourceQueryParam.getMethod());
        if (resourceQueryParam.getCreatedTimeStart() != null && resourceQueryParam.getCreatedTimeEnd() != null) {
            queryWrapper.apply("date_format(created_time,'%Y-%m-%d') >= date_format('" + convert.format(resourceQueryParam.getCreatedTimeStart()) + "','%Y-%m-%d')");
            queryWrapper.apply("date_format(created_time,'%Y-%m-%d') <= date_format('" + convert.format(resourceQueryParam.getCreatedTimeEnd()) + "','%Y-%m-%d')");
        }
        if (!resourceQueryParam.getEnabled()) {
            queryWrapper.eq("enabled", 0);
        }
        return this.list(queryWrapper);
    }


    @Override
    public List<Resource> getAll() {

        return this.list();
    }

    @Override
    @Transactional
//    @Cached(name = "resource4user::", key = "#username", cacheType = CacheType.BOTH)
    public List<Resource> query(String username) {
        //根据用户名查询到用户所拥有的角色
        User user = userService.getByUniqueId(username);
        List<Role> roles = roleService.query(user.getId());
        //提取用户所拥有角色id列表
        Set<String> roleIds = roles.stream().map(role -> role.getId()).collect(Collectors.toSet());
        //根据角色列表查询到角色的资源的关联关系
        List<RoleResource> roleResources = roleResourceService.queryByRoleIds(roleIds);
        //根据资源列表查询出所有资源对象
        Set<String> resourceIds = roleResources.stream().map(roleResource -> roleResource.getResourceId()).collect(Collectors.toSet());
        //根据resourceId列表查询出resource对象
        return (List<Resource>) this.listByIds(resourceIds);
    }

//    @Override
//    @PostConstruct
//    public boolean overload() {
//        List<Resource> resources = this.list(new QueryWrapper<>());
//        resources.forEach(gatewayRoute ->
//                gatewayRouteCache.put(gatewayRoute.getRouteId(), gatewayRouteToRouteDefinition(gatewayRoute))
//        );
//        log.info("全局初使化网关路由成功!");
//        return true;
//    }
}
